#include "ota_update.h"
#include <unistd.h>
#include <string.h>

typedef struct _S_PACKAGE
{
    char appId[128];
    int otaType;
    char fileId[128];
    char appName[128];
    char appVersion[128];
    char fileName[256];
    int statusPos;
} S_PACKAGE, *PS_PACKAGE;

static char g_childDeviceLastid[4096];
static int g_childDeviceLastCode;
static int g_childDeviceLast105;
int nvr_EagleEyeSMG_update_tq(char *dir,char *filename, ST_IOTA_LOG_RES *progressDecs);

/// @brief
/// @param param
/// @return
static int status_package_update(PS_PACKAGE p_sPackage, IOTA_OTA_UPDATE_PARAM *pparam, ST_IOTA_LOG_RES *progressDecs, int isPackage)
{
    char statusPath_cmd[4096] = {0};
    char pathbuf[255] = {0};
    memcpy(pathbuf, pparam->filename, strstr(pparam->filename, ".tar.gz") - pparam->filename);
    struct stat file_inf = {0};
    sprintf(statusPath_cmd, "%s/%s/%s/%s_upgradeStatus.ini", APP_FILE_PATH, pparam->fileId, pathbuf, p_sPackage->fileName);
    int ret = stat(statusPath_cmd, &file_inf);

    if (0 == file_inf.st_size || ret < 0)
    {
        sleep(2);
        return -9;
    }
    sprintf(statusPath_cmd, "cat %s/%s/%s/%s_upgradeStatus.ini", APP_FILE_PATH, pparam->fileId, pathbuf, p_sPackage->fileName);
    FILE *fp = NULL;
    char buf[256];
    int index = 0;
    if ((fp = popen(statusPath_cmd, "r")) == NULL)
    {
        // pclose(fp);
        sleep(2);
        return -9;
    }
    int flag = 0;
    dzlog_info("statusPath_cmd[%s]", statusPath_cmd);
    while (fgets(buf, 255, fp) != NULL)
    {
        if (strstr(buf, "No such file or directory"))
        {
            pclose(fp);
            sleep(2);
            return -9;
        }

        dzlog_info("buf[%s]index[%d]p_sPackage->statusPos[%d]", buf, index, p_sPackage->statusPos);

        if (index >= p_sPackage->statusPos)
        {
            char *p = strstr(buf, ":");
            if (!p)
            {
                // pclose(fp);
                // return -1;
                continue;
            }
            (buf[strlen(buf) - 1] == '\n') && (buf[strlen(buf) - 1] = '\0');
            p++;

            if (strstr(p, "105"))
            {
                char *p1 = strstr(p, "&");
                if (!p1)
                {
                    pclose(fp);
                    return -1;
                }
                *p1++ = '\0';

                if (isPackage == 1)
                    send_package_progress(atoi(p), atoi(p1), p_sPackage->appId, p_sPackage->appName, p_sPackage->appVersion, progressDecs);
                else if(isPackage == 3)
                	send_childDevice_progress(atoi(p), atoi(p1),p_sPackage->fileName, progressDecs);
                else
                    send_progress(atoi(p), atoi(p1), progressDecs);
                dzlog_info("105 buf[%s]index[%d]p_sPackage->statusPos[%d]", buf, index, p_sPackage->statusPos);
            }
            else
            {
                if (isPackage == 1)
                    send_package_progress(atoi(p), -1, p_sPackage->appId, p_sPackage->appName, p_sPackage->appVersion, progressDecs);
                else if(isPackage == 3)
                	send_childDevice_progress(atoi(p), -1,p_sPackage->fileName, progressDecs);
                else
                    send_progress(atoi(p), -1, progressDecs);
                dzlog_info("not 105[%s]index[%d]p_sPackage->statusPos[%d]", buf, index, p_sPackage->statusPos);
            }
            if (atoi(p) >= 200)
            {
                // pclose(fp);
                p_sPackage->statusPos = 0 - atoi(p);
                // return 200;
            }
            flag = 1;
        }
        index++;
        usleep(200 * 1000);
    }
    if (p_sPackage->statusPos > -200)
    {
        p_sPackage->statusPos = index;
    }
    pclose(fp);
	
    if(0 == flag)
    {
    	return -3;
    }
    return 0;
}

/// @brief
/// @param param
/// @return
static int pro_package_update(IOTA_OTA_UPDATE_PARAM param, ST_IOTA_LOG_RES *progressDecs)
{
    ///
    char packagePath[4096] = {0};
    char pathbuf[255] = {0};
    memcpy(pathbuf, param.filename, strstr(param.filename, ".tar.gz") - param.filename);
    sprintf(packagePath, "%s/%s/%s", APP_FILE_PATH, param.fileId, pathbuf);
    // char *pcJson = NULL;
    char file_path[1025] = {0};

    sprintf(file_path, "%s/install.json", packagePath);
    struct stat file_inf = {0};

    stat(file_path, &file_inf);

    if (file_inf.st_size <= 0)
    {
        dzlog_error("file_path :%s not exsits!!!!!!!!", file_path);
        return -1;
    }

    FILE *fp;

    if ((fp = fopen(file_path, "r")) == NULL)
    {
        dzlog_error("file_path :%s error fopen!!!!!!!!", file_path);
        return -2;
    }
    char *pcJson = (char *)malloc(sizeof(char) * (file_inf.st_size + 1));
    fread(pcJson, 1, file_inf.st_size, fp);
    fclose(fp);

    ///
    dzlog_info(pcJson);
    printf("%s\n", pcJson);

    cJSON *json = NULL;
    cJSON *subpackage = NULL;
    cJSON *info = NULL;

    /// req
    char name[128] = {0};
    int Num = 0;

    char appId[128] = {0};
    int otaType = 0;
    char appName[128] = {0};
    char appVersion[128] = {0};
    char fileName[128] = {0};
    int isfirmware = 0;
    int isalgorithm = 0;
    int isEagleEyeSMG = 0;
    
    char nvr_firmware_info[255] = {0};

    json = cJSON_Parse(pcJson);
    dzlog_info("1111111111111111111");
    if (json)
    {
        strcpy(name, cJSON_GetObjectItem(json, "name")->valuestring);
        Num = cJSON_GetObjectItem(json, "num")->valueint;
        PS_PACKAGE ps_package = (PS_PACKAGE)malloc(sizeof(S_PACKAGE) * Num);

        if (cJSON_HasObjectItem(json, "subpackage"))
        {
            dzlog_info("333333333333333333333333 Num[%d]", Num);
            subpackage = cJSON_GetObjectItem(json, "subpackage");
            dzlog_info("333333333333333333333333 Num[%d]", Num);

            int i = 0;
            PS_PACKAGE ps_buf = ps_package;
            FILE *fp = fopen("./nvr_firmware.ini", "w");
            
            FILE *fp1 = fopen("./nvr_algorithm.ini", "w");
            
            FILE *fp2 = fopen("./nvr_EagleEyeSMG.ini", "w");
            for (i = 0; i < cJSON_GetArraySize(subpackage); i++)
            {
                dzlog_info("333333333333333333333333 i[%d]", i);

                info = cJSON_GetArrayItem(subpackage, i);
                strcpy(ps_buf->fileId, cJSON_GetObjectItem(info, "fileId")->valuestring);
                strcpy(ps_buf->appId, cJSON_GetObjectItem(info, "appId")->valuestring);
                ps_buf->otaType = cJSON_GetObjectItem(info, "otaType")->valueint;
                strcpy(ps_buf->appName, cJSON_GetObjectItem(info, "appName")->valuestring);
                strcpy(ps_buf->appVersion, cJSON_GetObjectItem(info, "appVersion")->valuestring);
                strcpy(ps_buf->fileName, cJSON_GetObjectItem(info, "fileName")->valuestring);
                ps_buf->statusPos = 0;
                if (ps_buf->otaType == 1)
                {
                    isfirmware = 1;
                    if (fp)
                    {
                        sprintf(nvr_firmware_info, "%s,%s,%s\n", ps_buf->appId, ps_buf->appName, ps_buf->appVersion);
                        fputs(nvr_firmware_info, fp);
                    }
                }
                if (ps_buf->otaType == 3)
                {
                    isalgorithm = 1;
                    if (fp1)
                    {
                        sprintf(nvr_firmware_info, "%s,%s,%s\n", ps_buf->appId, ps_buf->appName, ps_buf->appVersion);
                        fputs(nvr_firmware_info, fp1);
                    }
                }
                
                if (ps_buf->otaType == 5)
                {
                    isEagleEyeSMG = 1;
                    if (fp2)
                    {
                        sprintf(nvr_firmware_info, "%s,%s,%s\n", ps_buf->appId, ps_buf->appName, ps_buf->appVersion);
                        fputs(nvr_firmware_info, fp2);
                    }
                }
                ps_buf++;
            }
            if (fp)
            {
                fclose(fp);
            }
            if (fp1)
            {
                fclose(fp1);
            }
            if (fp2)
            {
                fclose(fp2);
            }
        }

        cJSON_Delete(json);
        free(pcJson);

        if (isfirmware == 0)
        {
            system("rm -rf ./nvr_firmware.json");
            system("rm -rf ./nvr_firmware.ini");
            
        }
        if(isalgorithm == 0)
        {
		system("rm -rf ./nvr_algorithm.json");
		system("rm -rf ./nvr_algorithm.ini");
	}
	if(isEagleEyeSMG == 0)
	{
		system("rm -rf ./otaEagleEyeSMG.json");
		system("rm -rf ./nvr_EagleEyeSMG.ini");
	}
        ///
        int package = 0;
        int timeout = 0;
        int ret = -1;
        while (package < Num)
        {
            if (timeout > 150)
            {
                return 558;
            }
            if(timeout == 0)
            {
            	sleep(2);
            }
            //timeout++;
            dzlog_info("333333333333333333333333 package[%d]Num[%d]", package, Num);

            int i = 0;
            PS_PACKAGE ps_buf = ps_package;
            package = 0;
            for (i = 0; i < Num; i++)
            {
                /// test
                /*
                send_package_progress(101, -1, ps_buf->appId,ps_buf->appName , ps_buf->appVersion ,progressDecs);
                send_package_progress(103, -1, ps_buf->appId,ps_buf->appName , ps_buf->appVersion ,progressDecs);
                send_package_progress(105, 100, ps_buf->appId,ps_buf->appName , ps_buf->appVersion ,progressDecs);
                send_package_progress(107, -1, ps_buf->appId,ps_buf->appName , ps_buf->appVersion ,progressDecs);
                send_package_progress(200, -1, ps_buf->appId,ps_buf->appName , ps_buf->appVersion ,progressDecs);
                */

                /// test
                //if (ps_buf->statusPos == -200)
                if (ps_buf->statusPos <= -200 && ps_buf->statusPos > -300)
                {
                    package++;
                    if (ps_buf->otaType == 2)
                    {
                        IOTA_APP_CTRL app;
                        app.fileId = ps_buf->fileId;
                        app.appId = ps_buf->appId;
                        app.appVersion = ps_buf->appVersion;
                        app.appName = ps_buf->appName;
                        dzlog_info("5555555555555555555555 app.appId[%s],ps_buf->fileName[%s]", app.appId, ps_buf->fileName);
                        SqlDeleteApp(app.appId);
                        SqlDeleteAppInfoByAppName(app, ps_buf->fileName);
                        if (SqlAddAppInfo_V2(app, ps_buf->fileName) == false)
                        {
                            if (ps_package)
                            {
                                free(ps_package);
                            }
                            return 514;
                        }
                    }
                    ps_buf++;
                    continue;
                }
                //if (ps_buf->statusPos < -200)
                if (ps_buf->statusPos <= -300)
                {
                    if (ps_package)
                    {
                        free(ps_package);
                    }

                    return 0 - ps_buf->statusPos;
                }
                ret = status_package_update(ps_buf, &param, progressDecs, 1);
                if(ret < 0)
                {
                	timeout++;
                	sleep(2);
                }
                else
                {
                	timeout = 0;
                }
                if(package == Num-1&&ps_buf->otaType == 5 )
		{
		    	dzlog_info("6666666666666666 ps_buf->appId[%s],ps_buf->fileName[%s]", ps_buf->appId, ps_buf->fileName);
		    	
		    	char cmd[1024] = {0};
		    	sprintf(cmd, "cp %s/%s %s/%s", packagePath,ps_buf->fileName,APP_FILE_PATH, param.fileId);
		    	system(cmd);
		    	strcpy(param.filename,ps_buf->fileName);
		    	
		        send_package_progress(109, -1, ps_buf->appId,ps_buf->appName , ps_buf->appVersion ,progressDecs);
		        //char filename[1024] = {0};
		        //strcpy(filename,ps_buf->fileName);
		        dzlog_info("77777777777777 packagePath[%s],param.filename[%s]",packagePath, param.filename);
		        
		        if (ps_package)
		            {
		                free(ps_package);
		            }
		        sleep(10);

		    	return 109109;
		}
                ps_buf++;
            }
            
        }
        ///
        if (ps_package)
        {
            free(ps_package);
        }
        return 0;
    }
    dzlog_error("file_path :%s error json!!!!!!!!", file_path);

    return -3;
}

/// @brief 向上级发送进度
/// @param code
/// @param progress
/// @return
static bool send_childDevice_last(ST_IOTA_LOG_RES *progressDecs)
{
  
    if (g_childDeviceLastCode > 0)
    {
        if(g_childDeviceLastCode == 105)
        {
        	send_childDevice_progress(g_childDeviceLastCode, g_childDeviceLast105,g_childDeviceLastid, progressDecs);
        }
        else
        {
        	send_childDevice_progress(g_childDeviceLastCode, -1,g_childDeviceLastid, progressDecs);
        }
        
        return true;
    }
    else
    {
        return false;
    }
}
/// @brief
/// @param param
/// @return
static int pro_childDevice_update(IOTA_OTA_UPDATE_PARAM param, ST_IOTA_LOG_RES *progressDecs)
{
    if(strlen(param.subDeviceid) == 0)
    {
    	return -1;
    }
    int Num = 0;
    /*
    char *token = strtok(param.subDeviceid, ",");
    while (token != NULL)
    {
	Num++;
	// Get next token: 
	token = strtok(NULL, ",");

    }
    if(0 == Num)
    {
    	Num = 1;
    }*/
    char *p = param.subDeviceid;
    while(*p != '\0')
    {
    	if(*p == ',')
    	Num++;
    	p++;
    }
    Num++;
    PS_PACKAGE ps_package = (PS_PACKAGE)malloc(sizeof(S_PACKAGE) * Num);
    PS_PACKAGE ps_buf = ps_package;
    int i = 0;
    char *token = strtok(param.subDeviceid, ",");
    for(;i < Num;++i)
    {
	ps_buf->otaType = 13;
	ps_buf->statusPos = 0;
	if (token != NULL)
    	{
		strcpy(ps_buf->fileName, token);
		/* Get next token: */
		token = strtok(NULL, ",");

    	}
    	if(1 == Num)
    	{
    		strcpy(ps_buf->fileName, param.subDeviceid);
    	}
	
	ps_buf++;
    }
        int package = 0;
        int timeout = 1;
        int flag = 0;
        int ret = -1;
        memset(g_childDeviceLastid,0,sizeof(g_childDeviceLastid));
        g_childDeviceLastCode = 0;
        g_childDeviceLast105 = 0;
        while (package < Num)
        {
            if (timeout > 900)
            {
                return 558;
            }
            
            if(timeout == 1)
            {
            	sleep(2);
            }
            //timeout++;
            dzlog_info("0000000000000000000 package[%d]Num[%d]", package, Num);

            int i = 0;
            PS_PACKAGE ps_buf = ps_package;
            package = 0;
            for (i = 0; i < Num; i++)
            {
               
                if (ps_buf->statusPos <= -200)
                {
                    package++;
                   
                    
                    if (ps_buf->statusPos < -200)
                    {
                    	flag =1;
                    }
                    ps_buf++;
                    continue;
                }
               
                ret = status_package_update(ps_buf, &param, progressDecs, 3);
                if(ret < 0)
                {
                	timeout++;
                	if(timeout % 60 == 0)
            		{
            			send_childDevice_last(progressDecs);
            		}
            		sleep(2);
                }
                else
                {
                	timeout = 1;
                }
                ps_buf++;
            }
        }
        ///
        if (ps_package)
        {
            free(ps_package);
        }
        if(1 == flag)
        {
        	return 515;
        }
        return 0;
   
}

/// @brief 升级前检查
/// @param param
/// @return
int update_check(IOTA_OTA_UPDATE_PARAM param)
{
    // TODO app升级校验暂时先sleep 1秒
    if (param.otaType == 2 && param.deviceType == 0)
    {
        sleep(1);
        return 1;
    }
    return 0;
}
/// @brief 向上级发送进度
/// @param code
/// @param progress
/// @return
bool send_progress(int code, int progress, ST_IOTA_LOG_RES *progressDecs)
{
    if (progressDecs)
    {
        cJSON *json = NULL;
        // cJSON *body = NULL;
        char *pcJson;
        json = cJSON_CreateObject();
        // body = cJSON_CreateObject();
        char cTime[128] = {0};
        int ret = systemDate4(cTime);

        GF_GetGUID(progressDecs->iMid);
        // json
        cJSON_AddStringToObject(json, "mid", progressDecs->iMid);
        cJSON_AddNumberToObject(json, "code", code);
        cJSON_AddStringToObject(json, "deviceSn", progressDecs->deviceSn);
        cJSON_AddStringToObject(json, "replyId", progressDecs->replyId);
        cJSON_AddStringToObject(json, "zone", progressDecs->zone);
        cJSON_AddStringToObject(json, "node", progressDecs->node);
        cJSON_AddStringToObject(json, "msgTime", cTime);
        cJSON_AddStringToObject(json, "deviceId", progressDecs->deviceID);
        if (progress >= 0)
        {
            cJSON_AddNumberToObject(json, "installProgress", progress);
        }

        pcJson = cJSON_PrintUnformatted(json);
        ret = IOTA_SendMqtt("/v1/devices/ota/response", pcJson, strlen(pcJson));
        cJSON_Delete(json);
        free_s(pcJson);
        return true;
    }
    else
    {
        return false;
    }
}
/// @brief 向上级发送进度
/// @param code
/// @param progress
/// @return
bool send_package_progress(int code, int progress, char *appId, char *appName, char *appVersion, ST_IOTA_LOG_RES *progressDecs)
{
    cJSON *json = NULL;
    cJSON *body = NULL;
    char *pcJson;
    json = cJSON_CreateObject();
    body = cJSON_CreateObject();
    char cTime[128] = {0};
    int ret = systemDate4(cTime);
    if (progressDecs)
    {
        GF_GetGUID(progressDecs->iMid);
        // json
        cJSON_AddStringToObject(json, "mid", progressDecs->iMid);
        cJSON_AddNumberToObject(json, "code", code);
        cJSON_AddStringToObject(json, "deviceSn", progressDecs->deviceSn);
        cJSON_AddStringToObject(json, "replyId", progressDecs->replyId);
        cJSON_AddStringToObject(json, "zone", progressDecs->zone);
        cJSON_AddStringToObject(json, "node", progressDecs->node);
        cJSON_AddStringToObject(json, "msgTime", cTime);
        cJSON_AddStringToObject(json, "deviceId", progressDecs->deviceID);
        cJSON_AddStringToObject(json, "appId", appId);
        cJSON_AddStringToObject(json, "appName", appName);
        cJSON_AddStringToObject(json, "appVersion", appVersion);
        if (progress >= 0)
        {
            cJSON_AddNumberToObject(json, "installProgress", progress);
        }

        pcJson = cJSON_PrintUnformatted(json);
        //ret = IOTA_SendMqtt("/v1/devices/ota/response", pcJson, strlen(pcJson));
        while (1)
        {
            int ret2 = IOTA_SendMqtt("/v1/devices/ota/response", pcJson, strlen(pcJson));
            if (ret2 == 0)
            {
                break;
            }
            else
            {
                sleep(5);
            }
        }
        cJSON_Delete(json);
        free_s(pcJson);
        return true;
    }
    else
    {
        return false;
    }
}

/// @brief 向上级发送进度
/// @param code
/// @param progress
/// @return
bool send_childDevice_progress(int code, int progress,char *subDeviceId, ST_IOTA_LOG_RES *progressDecs)
{
    cJSON *json = NULL;
    cJSON *body = NULL;
    char *pcJson;
    json = cJSON_CreateObject();
    body = cJSON_CreateObject();
    char cTime[128] = {0};
    int ret = systemDate4(cTime);
    if (progressDecs)
    {
        GF_GetGUID(progressDecs->iMid);
        // json
        cJSON_AddStringToObject(json, "mid", progressDecs->iMid);
        cJSON_AddNumberToObject(json, "code", code);
        cJSON_AddStringToObject(json, "deviceSn", progressDecs->deviceSn);
        cJSON_AddStringToObject(json, "replyId", progressDecs->replyId);
        cJSON_AddStringToObject(json, "zone", progressDecs->zone);
        cJSON_AddStringToObject(json, "node", progressDecs->node);
        cJSON_AddStringToObject(json, "msgTime", cTime);
        cJSON_AddStringToObject(json, "deviceId", progressDecs->deviceID);
        cJSON_AddNumberToObject(json, "deviceType", 1);
        cJSON_AddStringToObject(json, "subDeviceId", subDeviceId);
        if (progress >= 0)
        {
            cJSON_AddNumberToObject(json, "installProgress", progress);
            g_childDeviceLast105 = progress;///
        }

        pcJson = cJSON_PrintUnformatted(json);
        g_childDeviceLastCode = code;///
        strcpy(g_childDeviceLastid,subDeviceId);///
        ret = IOTA_SendMqtt("/v1/devices/ota/response", pcJson, strlen(pcJson));
        cJSON_Delete(json);
        free_s(pcJson);
        return true;
    }
    else
    {
        return false;
    }
}

/// @brief EagleEyeSMG升级接口
/// @param param
/// @return
int nvr_EagleEyeSMG_update_107(IOTA_OTA_UPDATE_PARAM param, char *filename, ST_IOTA_LOG_RES *progressDecs)
{
    send_progress(107, -1, progressDecs);
    return 0;
}
/// @brief EagleEyeSMG升级接口
/// @param param
/// @return
int nvr_EagleEyeSMG_update_bak(IOTA_OTA_UPDATE_PARAM param, char *filename, ST_IOTA_LOG_RES *progressDecs)
{
    char cmd[4099] = {0};
    send_progress(103, -1, progressDecs);

    sleep(2);
    sprintf(cmd, "cd %s/%s && tar -zxvf %s", APP_FILE_PATH, param.fileId, param.filename);
    FILE *fp = popen(cmd, "r");
    if (fp == NULL)
    {
        return 506;
    }
    pclose(fp);

    srand(time(NULL));
    send_progress(105, 30 + rand() % 21, progressDecs);
    sleep(2);
    memset(cmd, 0, sizeof(cmd));
    sprintf(cmd, "rm -rf /userdata/tmp/app/EagleEyeSMG/otaTmp && mv %s/EagleEyeSMG /userdata/tmp/app/EagleEyeSMG/otaTmp && cd /userdata/tmp/app/EagleEyeSMG/otaTmp", APP_FILE_PATH);

    fp = popen(cmd, "r");
    if (fp == NULL)
    {
        return 505;
    }
    pclose(fp);

    memset(cmd, 0, sizeof(cmd));
    sprintf(cmd, "chmod u+x install.sh");

    fp = popen(cmd, "r");
    if (fp == NULL)
    {
        return 599;
    }
    pclose(fp);
    srand(time(NULL));
    send_progress(105, 60 + rand() % 21, progressDecs);
    system("sh install.sh");
    /*
     printf("Executing shell script...\n");
    int ret = execl("/bin/sh", "sh", "./script.sh", NULL);

    if (ret == -1) {
        printf("Error executing script\n");
        return 1;
    }

    // execl doesn't return unless there's an error
    // The following code will never be reached
    printf("Execution completed successfully\n");
    */
    /*

    sleep(1);
    send_progress(107, -1, progressDecs);
    */
    return 200;
}

static int checkPower(IOTA_OTA_UPDATE_PARAM param)
{
    char cmd[4096] = {0};

    char pathbuf[1023] = {0};
    memcpy(pathbuf, param.filename, strstr(param.filename, ".tar.gz") - param.filename);

    sprintf(cmd, "%s/%s/%s/install.sh", APP_FILE_PATH, param.fileId, pathbuf);
    dzlog_info(cmd);
    FILE *fp1 = fopen(cmd, "r");
    if (fp1 == NULL)
    {
        return 511;
    }
    fclose(fp1);
    memset(cmd, 0, sizeof(cmd));

    sprintf(cmd, "chmod 777 %s/%s/%s/install.sh", APP_FILE_PATH, param.fileId, pathbuf);
    system(cmd);
    sleep(1);
    return 0;
}
/// @brief EagleEyeSMG升级接口
/// @param param
/// @return
int nvr_EagleEyeSMG_update(IOTA_OTA_UPDATE_PARAM param, char *filename, ST_IOTA_LOG_RES *progressDecs)
{
    dzlog_info("nvr_EagleEyeSMG_update start");
    char cmd[512] = {0};
    send_progress(103, -1, progressDecs);
    sleep(2);

    tar_czf_exec(APP_FILE_PATH, param.fileId, param.filename);

    char path_tmp[255] = { 0 };
    sprintf(path_tmp, "%s/%s/EagleEyeSMG", APP_FILE_PATH, param.fileId);
    chmod_exec(path_tmp,"installOta.sh");

    sleep(1);

    sprintf(cmd, "%s/%s/EagleEyeSMG/installOta.sh", APP_FILE_PATH, param.fileId);
    FILE *fp1 = fopen(cmd, "r");
    if (fp1 == NULL)
    {
        return 515;
    }
    fclose(fp1);
    run_sh_script_background(path_tmp,"installOta.sh",NULL);
    dzlog_info("nvr_EagleEyeSMG_update 3");
    return 109;
}

/// @brief EagleEyeSMG升级接口
/// @param param
/// @return
int nvr_EagleEyeSMG_update_tq(char *dir,char *filename, ST_IOTA_LOG_RES *progressDecs)
{

    ///
    dzlog_info("nvr_EagleEyeSMG_update start");
    char cmd[4096] = {0};
    send_progress(103, -1, progressDecs);

    sleep(2);
    //sprintf(cmd, "cd %s && tar -zxvf %s", dir,filename);
    sprintf(cmd, "tar -zxvf %s/%s", dir,filename);
    FILE *fp = popen(cmd, "r");
    if (fp == NULL)
    {
        return 506;
    }
    pclose(fp);
    system(cmd);
    sleep(1);
    dzlog_info("nvr_EagleEyeSMG_update 1"); /*
     srand(time(NULL));
     send_progress(105, 30 + rand() % 21, progressDecs);
     sleep(2);*/

    sprintf(cmd, "chmod 777 %s/EagleEyeSMG/installOta.sh", dir);
    system(cmd);
    sleep(1);

    sprintf(cmd, "%s/EagleEyeSMG/installOta.sh", dir);
    dzlog_info(cmd);
    sleep(10000000);
    FILE *fp1 = fopen(cmd, "r");
    if (fp1 == NULL)
    {
        return 515;
    }
    fclose(fp1);
    memset(cmd, 0, sizeof(cmd));
    sprintf(cmd, "cd %s/EagleEyeSMG;sh installOta.sh &", dir);
    dzlog_info("nvr_EagleEyeSMG_update 2 shell cmd[%s]", cmd);
    system(cmd);
    dzlog_info("nvr_EagleEyeSMG_update 3");
    return 109;
}

/// @brief 整包升级接口
/// @param param整包
/// @return
int nvr_package_update(IOTA_OTA_UPDATE_PARAM param, char *filename, ST_IOTA_LOG_RES *progressDecs)
{
    char cmd[4096] = {0};

    char pathbuf[1023] = {0};
    memcpy(pathbuf, param.filename, strstr(param.filename, ".tar.gz") - param.filename);

    tar_czf_exec(APP_FILE_PATH, param.fileId, param.filename);


    sprintf(cmd, "%s/%s/%s/install.sh", APP_FILE_PATH, param.fileId, pathbuf);
    dzlog_info(cmd);
    FILE *fp1 = fopen(cmd, "r");
    if (fp1 == NULL)
    {
    	sprintf(cmd, "%s/%s/install.cap", APP_FILE_PATH, param.fileId);
    	FILE *fp3 = fopen(cmd, "ab");
    	if (fp3 == NULL)
    	{
        	return 515;	
    	}
    	fclose(fp3);
        return 506;
    }
    fclose(fp1);
    memset(cmd, 0, sizeof(cmd));

    char path_tmp[255] = { 0 };
    sprintf(path_tmp, "%s/%s/%s", APP_FILE_PATH, param.fileId, pathbuf);
    chmod_exec(path_tmp, "install.sh");

    sleep(1);
    int ret = run_sh_script_background(path_tmp, "install.sh",NULL);
    if (ret != 0)
    {
        return 513;
    }

    int pret = pro_package_update(param, progressDecs);
    if (pret < 0)
    {
        dzlog_error("pro_package_update pret:%d ", pret);
        return 599;
    }

    return pret;
}


/// @brief child devices升级接口
/// @param param
/// @return
int nvr_childDevice_update(IOTA_OTA_UPDATE_PARAM param, char *filename, ST_IOTA_LOG_RES *progressDecs)
{
    char *cmd= (char *)malloc(sizeof(char) * (strlen(param.subDeviceid) + 2048));
    if(!cmd)
    {
    	return 507;
    }
    char pathbuf[1023] = {0};
    memcpy(pathbuf, param.filename, strstr(param.filename, ".tar.gz") - param.filename);

    tar_czf_exec(APP_FILE_PATH, param.fileId, param.filename);

    sprintf(cmd, "%s/%s/%s/install.sh", APP_FILE_PATH, param.fileId, pathbuf);
    dzlog_info(cmd);
    FILE *fp1 = fopen(cmd, "r");
    if (fp1 == NULL)
    {
    	sprintf(cmd, "%s/%s/install.cap", APP_FILE_PATH, param.fileId);
    	FILE *fp3 = fopen(cmd, "ab");
    	if (fp3 == NULL)
    	{
    		free(cmd);
        	return 515;	
    	}
    	fclose(fp3);
    	free(cmd);
        return 506;
    }
    fclose(fp1);
    memset(cmd, 0, sizeof(cmd));

    char path_tmp[255] = { 0 };
    sprintf(path_tmp, "%s/%s/%s", APP_FILE_PATH, param.fileId, pathbuf);
    chmod_exec(path_tmp, "install.sh");
    sleep(1);
    int ret = run_sh_script_background(path_tmp, "installOta.sh", param.subDeviceid);
    if (ret != 0)
    {
    	free(cmd);
        return 513;
    }

    int pret = pro_childDevice_update(param, progressDecs);
    if (pret < 0)
    {
        dzlog_error("pro_package_update pret:%d ", pret);
        free(cmd);
        return 599;
    }
    
    free(cmd);
    return pret;
}

/// @brief 台区终端送检固件升级接口
/// @param param
/// @return
int nvr_firmware_update(IOTA_OTA_UPDATE_PARAM param, char *filename, ST_IOTA_LOG_RES *progressDecs)
{
    char cmd[215] = {0};
    sleep(2);

    tar_czf_exec(APP_FILE_PATH, param.fileId, param.filename);

    int ret = checkPower(param);
    if (ret != 0)
    {
        return ret;
    }
    FILE *fp3 = fopen("./nvr_firmware.ini", "w");
    if(fp3)
    {
    	fputs(param.patchVersion, fp3);
    	fclose(fp3);
    }
    
    memset(cmd, 0, sizeof(cmd));

    char path_tmp[255] = { 0 };
    sprintf(path_tmp, "%s/%s/EagleEyeSMG", APP_FILE_PATH, param.fileId);
    run_sh_script_background(path_tmp, "install.sh",NULL);

    S_PACKAGE s_buf = {0};
    s_buf.otaType = param.otaType;
    strcpy(s_buf.fileName, param.filename);
    sleep(2);
    if (status_package_update(&s_buf, &param, progressDecs, 0) == -9)
    {

    }
    return 109;
}

/// @brief nvr固件升级接口
/// @param param
/// @return
int nvr_firmware_update_bak(IOTA_OTA_UPDATE_PARAM param, char *filename, ST_IOTA_LOG_RES *progressDecs)
{
    char cmd[4096] = {0};
    send_progress(103, -1, progressDecs);
    sleep(2);
    sprintf(cmd, "cd %s/%s;tar -vxf %s", APP_FILE_PATH, param.fileId, param.filename);
    FILE *fp = popen(cmd, "r");
    if (fp == NULL)
    {
        return 506;
    }
    pclose(fp);

    srand(time(NULL));
    send_progress(105, 30 + rand() % 21, progressDecs);
    sleep(2);
    memset(cmd, 0, sizeof(cmd));
    sprintf(cmd, "cd %s/%s/%s;./install.sh", APP_FILE_PATH, param.fileId, param.patchName);

    fp = popen(cmd, "r");
    if (fp == NULL)
    {
        return 513;
    }
    pclose(fp);

    srand(time(NULL));
    send_progress(105, 60 + rand() % 21, progressDecs);
    sleep(1);
    send_progress(107, -1, progressDecs);
    return 0;
}
/// @brief common升级接口
/// @param param
/// @return
int nvr_common_update(IOTA_OTA_UPDATE_PARAM param, char *filename, ST_IOTA_LOG_RES *progressDecs)
{
    char cmd[4096] = {0};
    // send_progress(103, -1, progressDecs);
    sleep(2);
    sprintf(cmd, "cd %s/%s;tar -zxvf %s", APP_FILE_PATH, param.fileId, param.filename);
    FILE *fp = popen(cmd, "r");
    if (fp == NULL)
    {
        return 506;
    }
    pclose(fp);
    int ret = checkPower(param);
    if (ret != 0)
    {
        return ret;
    }

    memset(cmd, 0, sizeof(cmd));
    sprintf(cmd, "cd %s/%s/%s;sh install.sh &", APP_FILE_PATH, param.fileId, param.patchName);

    system(cmd);

    S_PACKAGE s_buf = {0};
    PS_PACKAGE ps_buf = &s_buf;
    s_buf.otaType = param.otaType;
    strcpy(s_buf.fileName, param.filename);
    int timeout = 0;
    status_package_update(&s_buf, &param, progressDecs, 0);
    while(1)
    {
    		if(timeout++ > 150)
    		{
    			break;
    		}
    		sleep(2);
    		if (ps_buf->statusPos <= -200)
    		{
                    if (ps_buf->otaType == 2 && ps_buf->statusPos == -200)
                    {
                        IOTA_APP_CTRL app;
                        app.fileId = param.fileId;
    			app.appId = param.patchId;
    			app.appVersion = param.patchVersion;
    			app.appName = param.patchName;
                        dzlog_info("5555555555555555555555 app.appId[%s],ps_buf->fileName[%s]", app.appId, ps_buf->fileName);
                        SqlDeleteApp(app.appId);
                        SqlDeleteAppInfoByAppName(app, ps_buf->fileName);
                        if (SqlAddAppInfo_V2(app, ps_buf->fileName) == false)
                        {
                           
                            return 514;
                        }
                    }
                    return 0 - ps_buf->statusPos;
     		}
      		
                status_package_update(&s_buf, &param, progressDecs, 0);
    }
    return 515;
}

/// @brief nvr app升级接口
/// @param param
/// @return
int nvr_app_update(IOTA_OTA_UPDATE_PARAM param, char *filename, ST_IOTA_LOG_RES *progressDecs)
{
    static int isNewAppmFlag = -1;
    if (isNewAppmFlag == -1)
    {
        char buf[128] = {0};
        char buf1[128] = {0};

        FILE *fp = popen("appm -v", "r");

        int n = fread(buf, 1, 128, fp);
        printf("appm -v:\n%s\n!!!", buf);
        dzlog_info("appm -v:\n%s\n!!!", buf);
        pclose(fp);
        if(strstr(buf,"not found"))
        {
        	return nvr_common_update(param, filename, progressDecs);
        }
        int i = 1;
        int j = 2;
        isNewAppmFlag = 0;
        for (; i < 100; ++i)
        {
            if (isNewAppmFlag == 1)
            {
                dzlog_info("isNewAppmFlag[%d]", isNewAppmFlag);
                break;
            }
            for (; j < 100; ++j)
            {
                isNewAppmFlag = 0;
                break;
                if (strstr(buf, buf1))
                {
                    isNewAppmFlag = 1;
                    break;
                }
            }
        }
    }
    isNewAppmFlag = 1;
    dzlog_info("isNewAppmFlag[%d]", isNewAppmFlag);
    char cmd[4096] = {0};
    // TODO app升级先sleep 2秒
    IOTA_APP_CTRL app;
    app.fileId = param.fileId;
    app.appId = param.patchId;
    app.appVersion = param.patchVersion;
    app.appName = param.patchName;
    if (param.otaType == 2 && param.deviceType == 0)
    {

        if (isNewAppmFlag)
        {
            sprintf(cmd, "cd %s/%s && appm -i -p %s", APP_FILE_PATH, param.fileId, param.filename);
        }
        else
        {
            sprintf(cmd, "cp %s/%s/%s  /userdata/tmp/package", APP_FILE_PATH, param.fileId, param.filename);
            system(cmd);
            sleep(1);
            sprintf(cmd, "cd /userdata/tmp/package && appm -i -p %s", param.filename);
        }
	
	if (isNewAppmFlag)
        {

		int tryAppm = 0;
		while(tryAppm++ < 3)
		{
			FILE *fp = popen(cmd, "r");
			if (fp == NULL)
			{	
		    		return 500;
	       		}
			 
		 	//int tryAppm = 0;
		 	//while(tryAppm++ < 3)
		 	//{
		    	int flag = 0;
		    	char buf[4096] = {0};
		    	while (fgets(buf, sizeof(buf), fp))
		    	{

				if (strstr(buf, "success"))
				{
				    SqlDeleteApp(app.appId);
				    SqlDeleteAppInfoByAppName(app, param.filename);
				    int ww = SqlAddAppInfo(app, param.filename);
				    // return 200;
				    flag = 1;
				} /*
				 else if (strstr(buf, "failed"))
				 {
				     dzlog_info("app install error[%s]", buf);
				     return 508;
				 }
				 else
				 {
				     dzlog_info("app install error[%s]", buf);
				     return 508;
				 }*/
			}
			pclose(fp);
			if (flag)
			{
					return 200;
			}
			else
			{
				dzlog_info("app install error[%s]", buf);
				//return 508;
				sleep(5);
				
				//system(cmd);
				continue;
		    	
		 	}
		 //return 508;
		}
	
		return 508;
	}
	FILE *fp = popen(cmd, "r");
        if (fp == NULL)
        {
                        return 500;
        }

        send_progress(103, -1, progressDecs);
        sleep(2);
        send_progress(105, 30 + rand() % 10, progressDecs);
        // 如果读取到信息，默认是安装出错了返回报错
        char buffer[140] = {0};
        if (fgets(buffer, sizeof(buffer), fp) > 0)
        {
            dzlog_info("appm -i error buffer = %s", buffer);
            pclose(fp);
            return 508;
        }

        pclose(fp);
        srand(time(NULL));
        send_progress(105, 60 + rand() % 10, progressDecs);
        sleep(2);
        send_progress(105, 100, progressDecs);

        SqlDeleteApp(app.appId);
        // if (SqlSearchAppidByVer(app.appId, app.appVersion))
        //{
        //     return 514;
        // }
        SqlDeleteAppInfoByAppName(app, param.filename);
        int ww = SqlAddAppInfo(app, param.filename);
        dzlog_info("SqlAddAppInfo ww[%d]", ww);

        char appname[100];
        const char *underscorePos = strchr(filename, '_');
        if (underscorePos != NULL)
        {
            size_t appLength = underscorePos - filename;
            strncpy(appname, filename, appLength);
            appname[appLength] = '\0';
            char trinity[256] = "chown -R tmp:tmp /userdata/tmp/app/";
            strcat(trinity, appname);
            dzlog_info("nvr_app_update trinity[%s]", trinity);
            system(trinity);
        }


        return 200;
    }
    return 0;
}

/// @brief nvr算法升级接口
/// @param param
/// @return
int nvr_algorithm_update(IOTA_OTA_UPDATE_PARAM param, char *filename, ST_IOTA_LOG_RES *progressDecs)
{
    return nvr_common_update(param, filename, progressDecs);
}

/// @brief 专门开个线程来读取发送
/// @param log_res
/// @return
int ota_read_progress(ota_update_progress *ota_progress)
{
    char load_file[100] = {0};
    IOTA_OTA_UPDATE_PARAM *param = ota_progress->param;
    ST_IOTA_LOG_RES *progressDecs = ota_progress->progressDecs;
    sprintf(load_file, "/userdata/tmp/package/%s/upgradeStatus.ini", param->subDeviceid);
    FILE *file = NULL;
    // 查询是否有文件
    while (access(load_file, F_OK))
    {
        usleep(50000);
    }

    file = fopen(load_file, "r");
    char line[100];
    int status = 0, progress = 0;
    long prev_file_size = 0;
    int timeout_count = 0; // 超时次数

    while (1)
    {
        // 获取当前文件大小
        fseek(file, 0, SEEK_END);
        long current_file_size = ftell(file);

        // 检查是否有新的 updateStatus 行
        if (current_file_size > prev_file_size)
        {
            // 将文件指针移动到新添加的部分
            fseek(file, prev_file_size, SEEK_SET);
            // printf("current = %d prev_file_size = %d", current_file_size, prev_file_size);
            //  读取新添加的行
            while (fgets(line, sizeof(line), file))
            {
                if (strncmp(line, "updateStatus:", 12) == 0)
                {

                    char *ptr = strchr(line, ':');
                    char *progressPtr = strchr(line, '&');
                    if (ptr)
                    {
                        // 提取状态信息
                        status = atoi(ptr + 1);

                        // 如果找到进度信息
                        if (progressPtr)
                        {
                            progress = atoi(progressPtr + 1);
                        }
                        else
                        {
                            progress = -1;
                        }
                    }

                    if (status < 100)
                    {
                        continue;
                    }

                    dzlog_debug("status = %d progress = %d\n", status, progress);

                    if (status == 200 || status > 500)
                    {
                        break;
                    }
                    send_progress(status, progress, progressDecs);
                }
            }

            // 重置超时计数器
            timeout_count = 0;
            prev_file_size = current_file_size;
        }
        else
        {
            // 如果 2 秒内没有新的 updateStatus 行,则增加超时计数器
            timeout_count++;
            if (timeout_count >= 150)
            {
                dzlog_debug("timeout over 150 turn ,exit");
                break;
            }
            sleep(2);
        }
    }
    fclose(file);
}

/// @brief nvr配置升级接口
/// @param param
/// @return
int nvr_config_update_bak(IOTA_OTA_UPDATE_PARAM param, char *filename, ST_IOTA_LOG_RES *progressDecs)
{
    char cmd[100] = {0};
    send_progress(103, -1, progressDecs);
    sleep(2);
    sprintf(cmd, "cd %s/%s;tar -vxf %s", APP_FILE_PATH, param.fileId, param.filename);
    FILE *fp = popen(cmd, "r");
    if (fp == NULL)
    {
        return 506;
    }
    pclose(fp);
    int ret = checkPower(param);
    if (ret != 0)
    {
        return ret;
    }

    srand(time(NULL));
    send_progress(105, 30 + rand() % 21, progressDecs);
    sleep(2);
    memset(cmd, 0, sizeof(cmd));
    sprintf(cmd, "cd %s/%s/%s;./install.sh", APP_FILE_PATH, param.fileId, param.patchName);

    fp = popen(cmd, "r");
    if (fp == NULL)
    {
        return 513;
    }
    pclose(fp);

    srand(time(NULL));
    send_progress(105, 60 + rand() % 21, progressDecs);
    sleep(1);
    send_progress(107, -1, progressDecs);
    return 200;
}
int nvr_config_update(IOTA_OTA_UPDATE_PARAM param, char *filename, ST_IOTA_LOG_RES *progressDecs)
{
	return nvr_common_update(param, filename, progressDecs);
}

int sub_update(IOTA_OTA_UPDATE_PARAM param, ST_IOTA_LOG_RES *progressDecs)
{
    int ret = 200;
    char cmd[100] = {0};
    if (param.deviceType == 1 && strlen(param.subDeviceid) == 0)
    {
        dzlog_error("subid is null");
        return 422;
    }
    ota_update_progress *ota;
    ota->param = &param;
    ota->progressDecs = progressDecs;
    // 进度发送分线程
    pthread_t thread;
    pthread_attr_t attr;
    // 初始化线程属性
    pthread_attr_init(&attr);

    // 将线程设置为分离状态
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    // 创建线程
    pthread_create(&thread, &attr, ota_read_progress, ota);

    // 销毁线程属性对象
    pthread_attr_destroy(&attr);

    sprintf(cmd, "sh /userdata/tmp/package/subUpgrade.sh %d %s/%s/%s %s %s", param.otaType, APP_FILE_PATH, param.fileId, param.filename, param.patchVersion, param.subDeviceid);

    dzlog_debug("cmd = %s", cmd);
    FILE *pcmd = popen(cmd, "r");
    if (pcmd == NULL)
    {
        return 506;
    }
    pclose(pcmd);

    // 结束后从这里来返回最终状态码
    char load_file[100] = {0};
    sprintf(load_file, "/userdata/tmp/package/%s/upgradeStatus.ini", param.subDeviceid);

    FILE *fp = fopen(load_file, "r");
    if (fp == NULL)
    {
        return 506;
    }

    char line[100];
    char *last_line = NULL;
    int time_out = 0;
    // 定位到文件末尾
    while (1)
    {
        fseek(fp, 0, SEEK_END);
        long file_size = ftell(fp);
        // 如果文件为空,返回NULL
        if (file_size == 0)
        {
            ret = 513;
            break;
        }
        // 从文件末尾开始向前搜索换行符
        while (file_size > 0)
        {
            fseek(fp, -2, SEEK_CUR);
            char c = fgetc(fp);
            file_size--;
            // printf("file_size = %d c = %c\n", file_size, c);
            if (c == '\n')
            {
                break;
            }
        }
        // 如果读取不到回车则认为这个只有一行，重置读取
        if (file_size == 0)
        {
            rewind(fp);
        }

        int status;
        // 读取最后一行
        fgets(line, 100, fp);
        last_line = strdup(line);
        dzlog_debug("last_line = %s\n", last_line);
        if (strncmp(last_line, "updateStatus:", 12) == 0)
        {

            char *ptr = strchr(last_line, ':');
            // 提取状态信息
            if (ptr)
            {
                status = atoi(ptr + 1);
                if (status == 200 || status > 500)
                {
                    ret = status;
                    free(last_line);
                    break;
                }
            }
        }
        free(last_line);
        // 五分钟没更新退出
        if (time_out > 150)
        {
            break;
        }

        time_out++;
        sleep(2);
    }
    fclose(fp);

    char new_name[200] = {0};
    sprintf(new_name, "/userdata/tmp/package/%s/%s%s_upgradeStatus.ini", param.subDeviceid, param.patchId, param.patchVersion);

    if (rename(load_file, new_name) == 0)
    {
        dzlog_info("new update file name %s", new_name);
    }
    else
    {
        dzlog_info("rename upgradeStatus.ini error");
    }

    return ret;
}
